#include "Int_EEPROM.h"

// 静态函数：写一个页内写入数据
// @param addr  要写入的地址
// @param datas 要写入的数据
// @param len   要写入的长度，不能超过一页
static void Int_EEPROM_WriteIntoPage(uint8_t addr, uint8_t *datas, uint8_t len)
{
    // 发送起始信号
    Dri_I2C2_Start();

    // 发送从设备地址+写标识 并接收应答信号
    Dri_I2C2_TransmitAddress(DEV_ADDR_W);

    // 发送内部字节地 并接收应答信号
    Dri_I2C2_TransmitByte(addr);

    // 循环发送要写入的字节，每发送一个字节都要接收一个应答信号
    for (uint8_t i = 0; i < len; i++)
    {
        Dri_I2C2_TransmitByte(datas[i]);
    }

    // 发送停止信号
    Dri_I2C2_Stop();

    // 延时，让EEPROM完成写周期
    Delay_ms(5);
}

/**
 * @brief 向EEPROM中指定位置写入指定长度的数据
 *
 * @param addr      要写入的位置（内部字节地址）
 * @param datas     要写入的数据
 * @param len       要写入的长度
 */
void Int_EEPROM_WriteData(uint8_t addr, uint8_t *datas, uint16_t len)
{
    // 定义变量
    uint8_t page_remain = 0;

    while (1)
    {
        // 计算当前页剩余可写入长度
        page_remain = 16 - addr % 16;

        // 如果当前页剩余长度不够
        if (len > page_remain)
        {
            // 先写满当前页剩余空间
            Int_EEPROM_WriteIntoPage(addr, datas, page_remain);

            // 写入位置后移
            addr += page_remain;
            // 要写入的数据指针后移
            datas += page_remain;
            // 要写入长度减掉已写入部分
            len -= page_remain;
        }
        // 如果当前页剩余长度足够
        else
        {
            // 将当前数据写入一页
            Int_EEPROM_WriteIntoPage(addr, datas, len);
            // 结束本函数，写入操作完成
            return;
        }
    }
}

/**
 * @brief 从EEPROM中指定位置读取指定长度的数据
 *
 * @param addr  要读取的位置
 * @param datas 将读取到的数据存入该地址处
 * @param len   要读取的长度
 */
void Int_EEPROM_ReadData(uint8_t addr, uint8_t *datas, uint16_t len)
{
    // 伪写 ---------------------------------------
    // 发送起始信号
    Dri_I2C2_Start();

    // 发送从设备地址+写标识，并接收应答信号
    Dri_I2C2_TransmitAddress(DEV_ADDR_W);

    // 发送字节地址，并接收应答信号
    Dri_I2C2_TransmitByte(addr);

    // 正式读 -------------------------------------
    // 发送起始信号
    Dri_I2C2_Start();

    // 发送从设备地址+读表示，并接收应答信号
    Dri_I2C2_TransmitAddress(DEV_ADDR_R);

    // 循环接收从EEPROM中读取的字节，每接收一个字节都回复一个应答信号
    for (uint16_t i = 0; i < len; i++)
    {
        // 发送应答信号， ACK控制位需要在接收字节之前设置
        // 如果是接收最后一个字节
        if (i == len - 1)
        {
            // 发送NACK信号，EEPROM会停止发送
            Dri_I2C2_TransmitACK(1);
            // 发送停止信号, STOP控制位需要提前设置
            Dri_I2C2_Stop();
        }
        // 如果接收的不是最后一个字节
        else
        {
            // 发送ACK
            Dri_I2C2_TransmitACK(0);
        }

        // 将接收到的字节存入datas
        datas[i] = Dri_I2C2_ReceiveByte();
    }
}
